package com.gitee.taotaojs.util.number;

import com.gitee.taotaojs.util.ConstantUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
 * @author TaoTaojs
 * @date 2020/7/8 11:28 AM
 * <p>Description</p>
 * <h1>大数工具类</h1>
 * <h2>简介</h2>
 * 大数据工具类
 * <h3>主要功能：</h3>
 * <ol>
 *     <li>两个数字字符串之间的运算</li>
 *     <li>各个格式化处理</li>
 *     <li>大数字符串之间的比较</li>
 * </ol>
 * 关联类:
 * 参考链接：
 * History: <br/>
 * <author>        <time>                      <version>          <desc>
 * TaoTaojs        2020/7/8 11:28 AM                V1.0          两个数字字符串之间的运算，各种格式化处理，大数字符串之间比较
 */
public final class BigDecimalUtil {

    private BigDecimalUtil(){}

    /**
     * 格式化精度
     *
     * @param v 双精度数字
     * @param point 小数位数
     * @return double 指定精度的数字
     */
    public static String format(double v, int point) {
        BigDecimal b = BigDecimal.valueOf(v);
        return b.setScale(point, BigDecimal.ROUND_HALF_UP).toString();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static String format(BigDecimal v, int point) {
        return v.setScale(point, BigDecimal.ROUND_HALF_UP).toString();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static String format(String v, int point) {
        BigDecimal bigDecimal = percentOperation(v);
        return bigDecimal.setScale(point, BigDecimal.ROUND_HALF_UP).toString();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static String format(String v) {
        BigDecimal bigDecimal = percentOperation(v);
        return bigDecimal.toString();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static String format(BigDecimal v) {
        return v.stripTrailingZeros().toPlainString();
    }

    /**
     * 四舍五入进位
     * @param v 双精度
     * @param point 保留小数位数
     * @return 四舍五入进位的数字
     */
    public static Double formatRoundUp(double v, int point) {
        NumberFormat nf = NumberFormat.getInstance();
        //设置四舍五入
        nf.setRoundingMode(RoundingMode.HALF_UP);
        //设置最小保留几位小数
        nf.setMinimumFractionDigits(point);
        //设置最大保留几位小数
        nf.setMaximumFractionDigits(point);
        return Double.valueOf(nf.format(v));
    }

    /**
     * 格式化金额。带千位符
     * @param v 双精度数字
     * @return 格式化金额
     */
    public static String moneyFormat(Double v) {
        DecimalFormat formater = new DecimalFormat();
        formater.setMaximumFractionDigits(ConstantUtil.TWO);
        formater.setGroupingSize(ConstantUtil.THREE);
        formater.setRoundingMode(RoundingMode.FLOOR);
        return formater.format(v.doubleValue());
    }

    /**
     * 带小数的显示小数。不带小数的显示整数
     * @param d 数字
     * @return 带小数的显示小数。不带小数的显示整数
     */
    public static String doubleTrans(Double d) {
        if (Math.round(d) - d == 0) {
            return String.valueOf((long) d.doubleValue());
        }
        return String.valueOf(d);
    }

    /**
     * BigDecimal 相加
     * @param v1 数字1
     * @param v2 数字2
     * @return double 相加后的值
     */
    public static Double add(double v1, double v2) {
        BigDecimal n1 = BigDecimal.valueOf(v1);
        BigDecimal n2 = BigDecimal.valueOf(v2);
        return n1.add(n2).doubleValue();
    }

    /**
     * BigDecimal 相减
     * @param v1 数字1
     * @param v2 数字2
     * @return double 相减后的值
     */
    public static Double subtract(double v1, double v2) {
        BigDecimal n1 = BigDecimal.valueOf(v1);
        BigDecimal n2 = BigDecimal.valueOf(v2);
        return n1.subtract(n2).doubleValue();
    }

    /**
     * BigDecimal 相乘
     * @param v1 数字1
     * @param v2 数字2
     * @return double 相乘后的值
     */
    public static Double multiply(double v1, double v2) {
        BigDecimal n1 = BigDecimal.valueOf(v1);
        BigDecimal n2 = BigDecimal.valueOf(v2);
        return n1.multiply(n2).doubleValue();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static BigDecimal multiply(String v1, String v2) {
        BigDecimal n1 = percentOperation(v1);
        BigDecimal n2 = percentOperation(v2);
        return n1.multiply(n2);
    }

    /**
     * BigDecimal 相除
     * @param v1 数字1
     * @param v2 数字2
     * @return double 相除后的值
     */
    public static Double divide(double v1, double v2) {
        BigDecimal n1 = BigDecimal.valueOf(v1);
        BigDecimal n2 = BigDecimal.valueOf(v2);
        return n1.divide(n2, ConstantUtil.TEN, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    @SuppressWarnings("checkstyle:JavadocMethod")
    public static BigDecimal divide(String v1, String v2) {
        BigDecimal n1 = percentOperation(v1);
        BigDecimal n2 = percentOperation(v2);
        return n1.divide(n2, ConstantUtil.TEN, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 处理百分号
     * @param str 数字字符串
     * @return 大数，且处理百分号
     */
    public static BigDecimal percentOperation(String str){
        if(NumberFormatUtil.isNumberPercent(str)){
            int incremental = ConstantUtil.BEST;
            if(str.contains(ConstantUtil.PERCENT)){
                incremental = ConstantUtil.TWO;
            }else if(str.contains(ConstantUtil.PERMILLAGE)){
                incremental = ConstantUtil.THOUSAND;
            }
            str = str.substring(0, str.length()-1);
            return divide(str, incremental+"");
        } else {
            return new BigDecimal(str);
        }
    }

    /**
     * 比较大小 小于0：v1 < v2 大于0：v1 > v2 等于0：v1 = v2
     * @param v1 数字1
     * @param v2 数字2
     * @return 返回关系int
     */
    public static int compare(double v1, double v2) {
        BigDecimal n1 = BigDecimal.valueOf(v1);
        BigDecimal n2 = BigDecimal.valueOf(v2);
        return n1.compareTo(n2);
    }

    /**
     * 智能调节java双精度对象进制误差，并返回真实数字
     * @param str 数字字符串（要使用isNumber判断一下哈，仅支持双精度与科学计数法）
     * @return 调节之后的数字对象，拿到直接toString即可
     */
    public static BigDecimal intelligentProcessingDigital(String str){
//        if(StringUtil.isBlank(str) || str.length()<16 || !NumberFormatUtil.isNumber(str)){
//            System.out.println("数据不正确，请检查 -> " + str);
//            return null;
//        }
        //找到字符串中最多的连续重复数字
        //排除最后一位与小数点之前的字符串
        StringBuilder sb = new StringBuilder(str);
        int eIndex = sb.indexOf("E");
        int pointIndex = sb.indexOf(".");
        if(pointIndex == -1){
            return new BigDecimal(str);
        }
        String numStr = sb.substring(
                pointIndex,
                eIndex != -1 ? eIndex : sb.length()
        );

        int numIndex = 0;
        char[] chars = numStr.toCharArray();
        Character flagChar = null;
        for (int i = chars.length-ConstantUtil.TWO; i >= 0; i--) {
            char c = chars[i];
            boolean isNumberChar = (c == '0' || c == '9');
            if(isNumberChar && flagChar == null){
                flagChar = c;
            } else {
                numIndex = i;
                break;
            }
        }
        if(flagChar == null){
            ++numIndex;
        }
        //拿到了index，直接采用四舍五入的方式获取值
        //判断是否有E，并拿到E后面的数字
        if(eIndex != -1){
            int intE = Integer.parseInt(str.substring(eIndex + 1));
            numIndex = numIndex - intE;
        }
        //判断小数点之前有几位(并不需要)
        BigDecimal bigDecimal = percentOperation(str);
        return bigDecimal.setScale(numIndex, BigDecimal.ROUND_HALF_UP);

    }

    /**
     * 使用java正则表达式去掉多余的.与0
     * @param s 字符串
     * @return 去掉尾部0和小数点的字符串
     */
    public static String subZeroAndDot(String s){
        if(s.contains(ConstantUtil.POINT)){
            //去掉多余的0
            s = s.replaceAll("0+?$", "");
            //如最后一位是.则去掉
            s = s.replaceAll("[.]$", "");
        }
        return s;
    }

}
